use std::net::ToSocketAddrs;
use tweeny_rpc::macros::service;

#[service(both_sides)]
pub(crate) trait CoolService {
    async fn heyhey(&self, x: usize) -> (String, usize);
    async fn yoyo(&self, u: String, v: [u32; 4]) -> Result<([String; 4], bool), i32>;
}

#[derive(Default)]
struct CoolServer {
    s: String,
}
impl<A: ToSocketAddrs> CoolService<A> for CoolServer {
    fn heyhey(
        &self,
        from: A,
        x: usize,
    ) -> impl std::future::Future<Output = (String, usize)> + Send {
        async { (String::new(), 0) }
    }
    fn yoyo(
        &self,
        from: A,
        u: String,
        v: [u32; 4],
    ) -> impl std::future::Future<Output = Result<([String; 4], bool), i32>> + Send {
        async {
            Ok((
                [String::new(), String::new(), String::new(), String::new()],
                true,
            ))
        }
    }
}

fn main() {
    use std::net::{SocketAddr, IpAddr, Ipv4Addr};
    use std::sync::Arc;
    use tokio::net::TcpStream;
    use tweeny_rpc::{client::error::CallError, courier::codec::DefaultSerder, server::Server};

    let s = CoolServer::default();
    let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
    let server = Server::new_via_tcp(Arc::new(CoolServiceRpcServ(s)), addr);
    tokio::spawn(async move {
        match server.await {
            Ok(server) => {
                let _ = server.serve().await;
            },
            Err(e) => println!("serve error"),
        }
    });
    tokio::spawn(async move {
        let (serving, handle) =
            CoolServiceClient::new(TcpStream::connect(addr).await.unwrap(), DefaultSerder);
        tokio::spawn(serving);
        match handle.heyhey(12, None).await {
            Ok(ok) => println!("{ok:?}"),
            Err(e) => match e {
                CallError::Panic => todo!(),
                CallError::TimeOut => todo!(),
                CallError::RespLost => todo!(),
                CallError::RespMismatch => todo!(),
                CallError::LocalRequestServingTaskEnded(e) => todo!(),
            },
        }
    });
}
